package com.jade.journal.format;

import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.Array;
import java.util.List;

import com.jade.framework.base.text.Escaper;
import com.jade.framework.base.text.SimpleEscaper;
import com.jade.framework.base.util.Parameters;
import com.jade.journal.JournalEntity;
import com.jade.journal.JournalEvent;
import com.jade.journal.JournalFormat;
import com.jade.journal.desc.JournalDesc;
import com.jade.journal.desc.field.Field;
import com.jade.journal.desc.field.Fields;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;

/**
 * 通用的格式化器。
 *
 * @author sky
 * @version 1.0 14-9-23 上午10:08
 */
public class GenericFormat implements JournalFormat
{
    protected String lineSep = "\r\n";
    protected char seperator = '|';
    private CharArrayWriter lineBuffer = new CharArrayWriter();
    private Escaper escaper = SimpleEscaper.getInstance();

    public void formatHeader(JournalEvent event, OutputStream out, String encoding)
            throws IOException
    {
        OutputStreamWriter writer = new OutputStreamWriter(out, encoding);
        JournalDesc desc = event.getDesc();
        Fields fields = desc.getFields();
        int fieldCount = fields.getFieldCount();
        for (int i = 0; i < fieldCount; i++) {
            Field field = fields.getField(i);
            if (i > 0) {
                print(seperator);
            }
            print(field.getName());
        }
        println(writer);
    }

    public void format(JournalEvent event, OutputStream out, String encoding)
            throws IOException
    {
        OutputStreamWriter writer = new OutputStreamWriter(out, encoding);
        Object item = event.getItem();
        JournalDesc desc = event.getDesc();
        Fields fields = desc.getFields();
        int fieldCount = fields.getFieldCount();
        int index = 0;
        for (int i = 0; i < fieldCount; i++) {
            Field field = fields.getField(i);
            Object value;
            if (field.isInternal()) {
                value = getInternalFiledValue(field, event);
            }
            else {
                value = getFiledValue(index++, field, item);
            }
            if (i > 0) {
                print(seperator);
            }
            print(value);
        }
        println(writer);
    }

    protected Object getFiledValue(int index, Field field, Object item)
    {
        if (item instanceof List) {
            return ((List)item).get(index);
        }
        else if (item.getClass().isArray()) {
            return Array.get(item, index);
        }
        else if (item instanceof Parameters) {
            return ((Parameters)item).getObject(field.getName());
        }
        else if (item instanceof JournalEntity) {
            try {
                return BeanUtils.getProperty(item, field.getName());
            }
            catch (Throwable t) {
                return null;
            }
        }
        return null;
    }

    protected Object getInternalFiledValue(Field field, JournalEvent event)
            throws IOException
    {
        String real = StringUtils.isNotBlank(field.getInternalName()) ? field.getInternalName() : field.getName();

        if ("time".equals(real)) {
            return event.getSimpleTime();
        }
        else if ("date".equals(real)) {
            return event.getSimpleDate();
        }
        else if ("datetime".equals(real)) {
            return event.getSimpleDate() + " " + event.getSimpleTime();
        }
        return null;
    }

    protected void print(Object value)
            throws IOException
    {
        if (value == null) {
            print("");
        }
        else if (value instanceof String) {
            escape((String)value);
        }
        else if (value instanceof Number) {
            print(value.toString());
        }
        else {
            print(value.toString());
        }
    }

    protected void print(String value)
            throws IOException
    {
        if (value == null) {
            print("");
        }
        else {
            print(value, 0, value.length());
        }
    }

    protected void print(String value, int off, int len)
            throws IOException
    {
        lineBuffer.write(value, off, len);
    }

    /**
     * 输出一个字符串
     *
     * @param value 字符串值
     */
    protected void escape(String value)
            throws IOException
    {
        escape(value, 0, value.length());
    }

    /**
     * 输出一个字符串
     *
     * @param value 字符串值
     * @param off   起始位置
     * @param len   长度
     */
    protected void escape(String value, int off, int len)
            throws IOException
    {
        escaper.escape(value, off, len, lineBuffer);
    }

    protected void println(OutputStreamWriter writer)
            throws IOException
    {
        lineBuffer.write(lineSep);
        lineBuffer.writeTo(writer);
        lineBuffer.reset();
        writer.flush();
    }

}
